--[[
usercb={
cb_conn_ready=function(cli),
cb_broken=function(cli),
cb_noti=function(cli,ch,bd),
cb_msg=function(cli,ch,bd)
}
funcb=function(cli,ch,bd)
--]]
require 'zdc.doc'
require 'zsvc.que'
require 'zsvc.packet'
require 'zsvc.evhandle'
require 'zsvc.cbmap'
require 'zsvc.notimap'
local monutil=require 'zsvc.monutil'
module(..., package.seeall)

local Clicon= {}
zsvc.evhandle.InitEvent(Clicon)
zsvc.cbmap.MakeInhMT(Clicon)

local Clicon_mt = {__metatable = {}, __index = Clicon}


function new(params)
	local obj = setmetatable({mon=params.mon,appaddr=params.appaddr,react=params.react,usercb=params.usercb or {},logger=params.logger,que=zsvc.que.new(),sp=zsvc.packet.new(),rp=zsvc.packet.new()}, Clicon_mt)
	obj.name='Clicon'
	obj.authed=false
	obj:init_cbmag()
	obj.DEFAULT_CALL_TIMEOUT=params.DEFAULT_CALL_TIMEOUT or 20
	obj:OnClose()
	obj.logger:info('Clicon start for ' .. logging.tostring(obj.appaddr))
	return obj
end

function Clicon:SetUserCB(ucb)
	self.usercb=ucb
end

function Clicon:GetBusy()
	return self.que:Count()
end
function Clicon:cb_conn_ready()
		self.connwait=nil
		self.logger:info('Clicon has connect to ' .. logging.tostring(self.appaddr))
		monutil.mon_start(self)
		if self.usercb.cb_conn_ready  then
			self.usercb.cb_conn_ready(self)
		end
end
function Clicon:OnClose()
	self:ResetCB()
	self.que:Clear() --TODO: reconnected and send left pkt
	if self.fd then
		self:_bv_close()
		self.logger:warn('Clicon close fd for ' .. logging.tostring(self.appaddr))
		monutil.mon_broke(self)
		self.fd:close()
	end
	self.fd=nil
	self.connwait=nil
	if self.usercb.cb_broken  then
		self.usercb.cb_broken(self)
	end
	self:_bv_init_connect(self.appaddr.host,self.appaddr.port)
end

function Clicon:OnMsg(packet)
	local pos,msg=packet:GetMsg()
	local ch,bd=msg.ch,msg.bd
	if ch.noti then
		print('noti  ',ch.noti)
		if self.usercb.cb_noti then
			self.usercb.cb_noti(self,ch,bd)
		end
	else
		local sn = ch.sn
		if sn and sn>0 then
			if self:DoCB(sn,ch,bd) then return end
		end
		if self.usercb.cb_msg then
			self.usercb.cb_msg(self,ch,bd)
		end
	end
end

local function getsn(con)
	local sn=con.cursn or 1
	con.cursn=sn+1
	if con.cursn>0x7fffffff then con.cursn=1 end
	return sn;
end

function Clicon:CallTimeout(cb,timeout,appid,nid,act,args)
	local sn=getsn(self)
	if cb then
		self:AddCBTimeout(sn,cb,timeout)
	end 
	local np=zsvc.packet.new()
	np:SetMsg(appid,{sn=sn},{node=nid,act=act,args=args})
	self:SendPacket(np)
	return sn
end

function Clicon:ACall(cb,appid,nid,act,args)
	return self:CallTimeout(cb,self.DEFAULT_CALL_TIMEOUT,appid,nid,act,args)
end
